/*
	The MIT License

	Copyright (c) 2008 IFMO/GameDev Studio

	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:

	The above copyright notice and this permission notice shall be included in
	all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
	THE SOFTWARE.
*/
// gui_manager.h - 

#pragma once


#define REG_ATTRIBUTE(attr, val)	attr = shell->RegisterVar(ObjName(#attr), val, SHLF_NEW|SHLF_NOSAVE)


class EGUIManager;
class EGUIFrame;
class EGUIDecoration;
class EGUILayout;


enum	guiAlign_t {
		GUI_ALIGN_FREE=0,
		GUI_ALIGN_MAX,
		GUI_ALIGN_CENTER,
		GUI_ALIGN_LEFT,
		GUI_ALIGN_RIGHT,
		GUI_ALIGN_TOP,
		GUI_ALIGN_BOTTOM,
	};


class EGUIEntity {
	public:
						EGUIEntity	( EGUIManager *fm, const char *name );
		virtual			~EGUIEntity	( void );
		
		const char		*GetName	( void ) const;
		
	private:
		string	name;
		
	protected:		
		const char		*ObjName	( const char *name ) const;
		EUserInterface	*ui;
		EGUIManager		*fm;
		IConsole		*con;
		IShell			*shell;
		IFileSystem		*fs;
		IRenderSystem	*rs;
	};


class ERectangle {
	public:
		ERectangle	( void ) : top_left(0,0), bottom_right(0,0) {}
		ERectangle	( float x, float y, float w, float h ) : top_left(x,y), bottom_right(x+w,y+h) {}
		ERectangle	( const EVec2 &tl, const EVec2 &br) : top_left(tl), bottom_right(br) {}
		
		EVec2	top_left, bottom_right;
	};


class EGUIFrame : public EGUIEntity {
	public:
							EGUIFrame	( EGUIManager *fm, const char *name, float x, float y, float w, float h );
		virtual				~EGUIFrame	( void );

		//	Message stuff :		
		virtual void		FMKeyPress			( uint code ) {};
		virtual void		FMKeyDown			( uint code ) {};
		virtual void		FMPaint				( void );
		virtual void		FMMouseUp			( uint button, float x, float y ) {};
		virtual void		FMMouseDown			( uint button, float x, float y ) {};
		virtual void		FMMouseClick		( uint button, float x, float y );
		virtual void		FMMouseIn			( void ) {};
		virtual void		FMMouseOut			( void ) {};
		virtual void		FMProcess			( float delta, float time );
		virtual void		FMResize			( float new_width, float new_height );
		virtual void		FMMove				( float new_x, float new_y );
		virtual	void		FMShowFrame			( void ) { is_visible = true; SetForeground(this); }
		virtual void		FMHideFrame			( void ) { is_visible = false; }
		virtual void		FMCtrlReadConfig	( void ) {}
		virtual void		FMCtrlWriteConfig	( void ) {}
		
		//	Frame property stuff :
		virtual bool		IsVisible			( void ) const { return is_visible; }  // should window be drawn
		virtual bool		IsEnabled			( void ) const { return is_visible; }  // should window receive message
		virtual uiRect_s	GetFrameRect		( void ) const { return frame_rect; }
		virtual uiRect_s	GetClientRect		( void ) const { return frame_rect; }	// by default both client and frame rect are the same
		virtual float		GetFrameOpacity		( void ) const { return frame_opacity; }
		
		//	Hierarchy stuff :
		virtual void		Attach				( EGUIFrame *child );
		uint				GetChildNum			( void ) { return (uint)children.size(); }
		EGUIFrame			*GetChild			( uint n ) { return children[n]; }
		EGUIFrame			*GetParent			( void ) { return parent; }
		void				SetForeground		( EGUIFrame *frame );

		//	Additional stuff :		
		void				SetLayout			( EGUILayout *layout ) { this->layout = layout; }
		void				SetDecoration		( EGUIDecoration *decor ) { this->decor = decor; }
		uint				GetLayoutIndex		( void ) const { return layout_index; }
		void				SetLayoutIndex		( uint index ) { layout_index = index; }
		void				Align				( void );
		
	private:
		EGUIFrame	*parent;
		vector<EGUIFrame*>	children;
		uint layout_index;

	protected:		
		EGUIDecoration	*decor;
		EGUILayout		*layout;
	public:
		IVar	*on_mouse_in;
		IVar	*on_mouse_out;
		IVar	*on_mouse_click;
		
	static void	Show_f		( EGUIFrame *self, int argc, char **argv ) { self->FMShowFrame(); }
	static void	Hide_f		( EGUIFrame *self, int argc, char **argv ) { self->FMHideFrame(); }
	static void SetAlign_f	( EGUIFrame *self, int argc, char **argv );
	
	protected:
		float		frame_opacity;
		float		align_spacing;
		guiAlign_t	align_mode;
		bool		is_visible;
		uiRect_s	frame_rect;
	};



class EGUIManager /*: public IUIObject*/ {
	public:
							EGUIManager	( EUserInterface *ui );
		virtual				~EGUIManager	( void );
		
		virtual void		KeyPress			( uint code );
		virtual void		KeyDown				( uint code );
		virtual void		MouseMove			( const mouseInput_s *mi );
		virtual void		Activate			( void );
		virtual void		Deactivate			( void );
		virtual void		Draw				( void );
		virtual const char	*Name				( void ) { return "frame_manager"; };
		
		//	Frame stuff :
		void				RegisterEntity		( EGUIEntity *frame );
		EGUIEntity			*FindEntity			( const char *name );
		void				GetAbsolutePosition	( EGUIFrame *frame, float &x, float &y );
		EGUIFrame			*GetFrameUnderCursor( void );
		void				SetForegroundFrame	( EGUIFrame *frame );
		void				SetActiveFrame		( EGUIFrame *frame );
		EGUIFrame			*GetActiveFrame		( void );
		
		void				DrawFrameRecursive	( EGUIFrame *frame );
		void				ProcessRecursive	( EGUIFrame *frame );

		//	Drawing stuff :		
		void				SetBranchColor		( const EVec4 &color );
		void				RevertBranchColor	( void );
		void				ResetView			( void );
		void				SetOffset			( float dx, float dy );
		EGUIDecoration		*GetDecoration		( void ) { return decor; }

	public:		
		EUserInterface	*ui;
	private:
		IConsole		*con;
		IShell			*shell;
		IFileSystem		*fs;
		IRenderSystem	*rs;
		
		stack<EVec4>		branch_color_stack;
		vector<EGUIEntity*> entities;
		EGUIFrame		*mb_down_frame[3];
		EGUIFrame		*frame_under_cursor;
		EGUIFrame		*root;
		EGUIFrame		*active_frame;
	
		EGUIDecoration	*decor;
		

		int mouse_x, mouse_y;
		mouseInput_s	old_mouse;
		
		
	static void GuiCreate_f		( EGUIManager *self, int argc, char **argv );
	static void GuiAttach_f		( EGUIManager *self, int argc, char **argv );
	static void	GuiSetLayout_f	( EGUIManager *self, int argc, char **argv );
	static void GuiRearrange	( EGUIManager *self, int argc, char **argv );
	static void GuiReadConfig_f	( EGUIManager *self, int argc, char **argv );
	static void GuiWriteConfig_f( EGUIManager *self, int argc, char **argv );
	};
	

	
//class EGUIManager	
	
	
	
	